
#include <REGX52.H>
#include <intrins.h>
#include "hardware_config.h"

void lcd_delay_ms(unsigned int ms)
{
    unsigned int i, j;
    for (i = 0; i < ms; i++)
    {
        for (j = 0; j < 123; j++)
            ;
    }
}
/**
 * us级别的延时函数
 */
void lcd_delay_us(unsigned int t)
{
    while (t--)
    {
        // no operation，1个NOP消耗1个机器周期
        // 晶振12MHZ  1/12000000  = 1/12 us  时钟周期
        // 1个机器周期等于12个时钟周期 1us
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
    }
}

/**
 * 读取忙状态标识
 * @param controller 0 cs1，1 cs2
 * @return 0: 准备好 ，1：繁忙，没有准备好
 */
bit lcd_read_busy(bit controller)
{
    bit is_busy = 0;
    // 读数据准备，数据线状态初始化
    LCD_DATA = 0xFF;
    // 读
    LCD_RW = 1;
    // 命令
    LCD_RS = 0;

    LCD_CS1 = (controller == 1);
    LCD_CS2 = (controller == 0);

    // 操作使能引脚
    LCD_E = 1;
    // 拉高保持
    lcd_delay_us(2);
    is_busy = (LCD_DATA & 0x80) ? 1 : 0;
    LCD_E = 0;
    return is_busy;
}

/**
 * 发送指令
 * @param cmd 一个字节的指令数据
 * @param controller 0 使用CS1， 1 使用CS2
 */
void lcd_write_command(unsigned char cmd,
                       unsigned char controller)
{
    // 等待忙状态标志位0
    while (lcd_read_busy(controller))
    {
        // 等待LCD准备好
        // lcd_delay_us(10);
    }

    // 准备数据引脚和控制引脚的电位
    // 开显示命令
    LCD_DATA = cmd;
    // 写
    LCD_RW = 0;
    // 命令
    LCD_RS = 0;

    LCD_CS1 = (controller == 1);
    LCD_CS2 = (controller == 0);

    // 操作使能引脚
    LCD_E = 1;
    // 拉高保持
    lcd_delay_us(2);
    LCD_E = 0;
}

/**
 * 发送数据
 * @param dat 一个字节的数据
 * @param controller 0 使用CS1， 1 使用CS2
 */
void lcd_write_data(unsigned char dat,
                    unsigned char controller)
{
    // 准备数据引脚和控制引脚的电位
    // 开显示命令
    LCD_DATA = dat;
    // 写
    LCD_RW = 0;
    // 数据
    LCD_RS = 1;

    LCD_CS1 = (controller == 1);
    LCD_CS2 = (controller == 0);

    // 操作使能引脚
    LCD_E = 1;
    // 拉高保持
    lcd_delay_us(2);
    LCD_E = 0;
}

/**
 * 在指定的页，指定的列上显示一个byte数据
 * @param page 0~7 页（行）
 * @param col 0~127 ，0~63 cs1  64~127 cs2
 */
void lcd_display_one_byte_in_page(
    unsigned char page,
    unsigned char col,
    unsigned char dat)
{
    bit controller = col >= 64;
    lcd_write_command(0xB8 | page, controller);
    // 0x40 | (col % 64)  结果等价于   0x40 | col
    lcd_write_command(0x40 | col, controller);
    lcd_write_data(dat, controller);
}

/**
 * 在指定的页，指定的列上显示一个byte数据
 * @param page 0~7 页（行）
 * @param col 0~127 ，0~63 cs1  64~127 cs2
 * @param count 写几次
 */
void lcd_display_same_bytes_in_page(
    unsigned char page,
    unsigned char col,
    unsigned char dat,
    unsigned char count)
{
    unsigned char i;
    if (col >= 64)
    {
        // 写cs2，不会跨屏
        lcd_write_command(0xB8 | page, 1);
        lcd_write_command(0x40 | col, 1);
        for (i = 0; i < count; i++)
        {
            lcd_write_data(dat, 1);
        }
    }
    else if (col + count < 64)
    {
        // 写cs1，不会跨屏
        lcd_write_command(0xB8 | page, 0);
        lcd_write_command(0x40 | col, 0);
        for (i = 0; i < count; i++)
        {
            lcd_write_data(dat, 0);
        }
    }
    else
    {
        // 先写cs1，写 (64 - col)个byte
        lcd_write_command(0xB8 | page, 0);
        lcd_write_command(0x40 | col, 0);
        for (i = 0; i < (64 - col); i++)
        {
            lcd_write_data(dat, 0);
        }

        // 再写cs2  count - (64 - col)
        lcd_write_command(0xB8 | page, 1);
        lcd_write_command(0x40, 1);
        for (i = 0; i < count - (64 - col); i++)
        {
            lcd_write_data(dat, 1);
        }
    }
}

void lcd_init()
{
    lcd_write_command(0x3F, 0);
    lcd_write_command(0x3F, 1);
    lcd_write_command(0xC0, 0);
    lcd_write_command(0xC0, 1);
}

void lcd_clear_screan()
{
    unsigned char i;
    for (i = 0; i < 8; i++)
    {
        lcd_display_same_bytes_in_page(i, 0, 0x00, 128);
    }
}

/**
 * 在指定的页，指定的列上显示一个byte数据
 * @param page 0~7 页（行）
 * @param col 0~127 ，0~63 cs1  64~127 cs2
 * @param byte_arr 数组指针
 * @param length 向屏幕写几个byte
 */
void lcd_display_bytes_in_page(
    unsigned char page,
    unsigned char col,
    unsigned char byte_arr[],
    unsigned int length)
{
    unsigned char i;
    if (col >= 64)
    {
        // 写cs2，不会跨屏
        lcd_write_command(0xB8 | page, 1);
        lcd_write_command(0x40 | col, 1);
        for (i = 0; i < length; i++)
        {
            lcd_write_data(byte_arr[i], 1);
        }
    }
    else if (col + length < 64)
    {
        // 写cs1，不会跨屏
        lcd_write_command(0xB8 | page, 0);
        lcd_write_command(0x40 | col, 0);
        for (i = 0; i < length; i++)
        {
            lcd_write_data(byte_arr[i], 0);
        }
    }
    else
    {
        // 先写cs1，写 (64 - col)个byte
        lcd_write_command(0xB8 | page, 0);
        lcd_write_command(0x40 | col, 0);
        for (i = 0; i < (64 - col); i++)
        {
            lcd_write_data(byte_arr[i], 0);
        }

        // 再写cs2  length - (64 - col)
        lcd_write_command(0xB8 | page, 1);
        lcd_write_command(0x40, 1);
        for (i = 0; i < length - (64 - col); i++)
        {
            lcd_write_data(byte_arr[(64 - col) + i], 1);
        }
    }
}

/**
 * 在指定的页，指定的列上显示一个byte数据
 * @param page 0~7 页（行）
 * @param col 0~127 ，0~63 cs1  64~127 cs2
 * @param words 一维数组指针
 * @param length_bytes 数组一共多少个byte
 * @param word_width_px 一个字宽度占几个像素
 * @param word_height_px 一个字高度占几个像素
 */
void lcd_display_words_in_page(
    unsigned char page,
    unsigned char col,
    unsigned char words[],
    unsigned int length_bytes,
    unsigned char word_width_px,
    unsigned char word_height_px)
{
    unsigned int i;
    unsigned char page_index;
    unsigned char page_count = word_height_px / 8;
    unsigned int one_word_bytes = word_width_px * page_count;
    for (i = 0; i < length_bytes; i += one_word_bytes)
    {
        for (page_index = 0; page_index < page_count; page_index++)
        {
            lcd_display_bytes_in_page(page + page_index, col, &words[i + page_index * word_width_px], word_width_px);
        }
        col += word_width_px;
    }
}